//+------------------------------------------------------------------+
//|                            gjm顶底 (MQL5)                        |
//+------------------------------------------------------------------+
#property copyright "2018 MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   6

//--- plot 1 (UpTrend Stop arrow)
#property indicator_label1  "UpTrend Stop"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot 2 (DownTrend Stop arrow)
#property indicator_label2  "DownTrend Stop"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrYellow
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot 3 (UpTrend Signal arrow)
#property indicator_label3  "UpTrend 信号"
#property indicator_type3   DRAW_ARROW
#property indicator_color3  clrRoyalBlue
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot 4 (DownTrend Signal arrow)
#property indicator_label4  "DownTrend 信号"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrRed
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- plot 5 (UpTrend line)
#property indicator_label5  "UpTrend 线"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrRoyalBlue
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1
//--- plot 6 (DownTrend line)
#property indicator_label6  "DownTrend 线"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrRed
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1

//--- input parameters
input int    布周期         = 20;
input int    布偏差         = 1;
input double 资金风险系数   = 1.00;    // Offset Factor
input int    显示信号样式   = 2;       // 1-显示Signals & Stops; 0-仅Stops; 2-仅Signals
input int    显示样线       = 1;       // 0-不显示, 1-显示辅助线
input int    计算棒数       = 2000;
input bool   使用报警       = false;

//--- indicator buffers
double 涨趋势箭[];
double 跌趋势箭[];
double 涨信号箭[];
double 跌信号箭[];
double 蓝涨线[];
double 红跌线[];

int    bandsHandle;
bool   已报涨 = false;
bool   已报跌 = false;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   // 绑定指标缓冲区
   ArraySetAsSeries(涨趋势箭, true);
   ArraySetAsSeries(跌趋势箭, true);
   ArraySetAsSeries(涨信号箭, true);
   ArraySetAsSeries(跌信号箭, true);
   ArraySetAsSeries(蓝涨线,   true);
   ArraySetAsSeries(红跌线,   true);
   
   SetIndexBuffer(0, 涨趋势箭, INDICATOR_DATA);
   SetIndexBuffer(1, 跌趋势箭, INDICATOR_DATA);
   SetIndexBuffer(2, 涨信号箭, INDICATOR_DATA);
   SetIndexBuffer(3, 跌信号箭, INDICATOR_DATA);
   SetIndexBuffer(4, 蓝涨线,   INDICATOR_DATA);
   SetIndexBuffer(5, 红跌线,   INDICATOR_DATA);

   // 设置箭头符号编码
   PlotIndexSetInteger(0, PLOT_ARROW, 159);
   PlotIndexSetInteger(1, PLOT_ARROW, 159);
   PlotIndexSetInteger(2, PLOT_ARROW, 233);
   PlotIndexSetInteger(3, PLOT_ARROW, 234);
   // 设置空值（EMPTY_VALUE 表示不绘制）
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(3, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(4, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetDouble(5, PLOT_EMPTY_VALUE, EMPTY_VALUE);

   // 指标短名称
   IndicatorSetString(INDICATOR_SHORTNAME, "BBands Stop(" + string(布周期) + ", " + string(布偏差) + ")");
   // 准备 Bollinger Band 句柄
   bandsHandle = iBands(_Symbol, _Period, 布周期, 0, 布偏差, PRICE_CLOSE);
   if(bandsHandle == INVALID_HANDLE)
      return INIT_FAILED;

   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Custom indicator calculation function                            |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   // 确保使用时间序列方式访问数组
   ArraySetAsSeries(time, true);
   ArraySetAsSeries(close, true);

   // 复制 Bollinger Band 上轨和下轨数据
   static double upperArr[], lowerArr[];
   ArraySetAsSeries(upperArr, true);
   ArraySetAsSeries(lowerArr, true);
   if(CopyBuffer(bandsHandle, 1, 0, rates_total, upperArr) < 0 ||
      CopyBuffer(bandsHandle, 2, 0, rates_total, lowerArr) < 0)
      return prev_calculated;

   // 计算实际使用的柱数
   int bars = MathMin(计算棒数, rates_total - 1);
   // 清空数组（填充0值，仿照MT4初始化）
   for(int i = bars; i >= 0; i--)
   {
      涨趋势箭[i] = 0;
      跌趋势箭[i] = 0;
      涨信号箭[i] = 0;
      跌信号箭[i] = 0;
      蓝涨线[i]   = EMPTY_VALUE;
      红跌线[i]   = EMPTY_VALUE;
   }

   // 主要计算循环（严格仿照MT4逻辑）
   if(bars > 布周期)
   {
      int 趋势 = 0;
      double 布上轨[25000], 布下轨[25000], 布外上轨[25000], 布外下轨[25000];
      
      for(int i = bars - 布周期 - 1; i >= 0; i--)
      {
         // 指标计算
         布上轨[i] = upperArr[i];
         布下轨[i] = lowerArr[i];
         
         // 价格所在趋势
         if(close[i] > 布上轨[i+1]) 趋势 = 1;
         if(close[i] < 布下轨[i+1]) 趋势 = -1;
         
         // 趋势为上时，下轨只允上移
         if(趋势 > 0 && 布下轨[i] < 布下轨[i+1]) 布下轨[i] = 布下轨[i+1];
         // 趋势为下时，上轨只允下移
         if(趋势 < 0 && 布上轨[i] > 布上轨[i+1]) 布上轨[i] = 布上轨[i+1];
         
         // 外轨
         布外上轨[i] = 布上轨[i] + 0.5 * (资金风险系数 - 1.0) * (布上轨[i] - 布下轨[i]);
         布外下轨[i] = 布下轨[i] - 0.5 * (资金风险系数 - 1.0) * (布上轨[i] - 布下轨[i]);
         
         // 趋势为上时，外下轨同样只允上移
         if(趋势 > 0 && 布外下轨[i] < 布外下轨[i+1]) 布外下轨[i] = 布外下轨[i+1];
         if(趋势 < 0 && 布外上轨[i] > 布外上轨[i+1]) 布外上轨[i] = 布外上轨[i+1];
         
         // 趋势向上时
         if(趋势 > 0)
         {
            // 前一涨趋箭为-1时（趋势切换点）
            if(显示信号样式 > 0 && 涨趋势箭[i+1] == -1.0)
            {
               涨信号箭[i] = 布外下轨[i];
               涨趋势箭[i] = 布外下轨[i];
               // 显示线
               if(显示样线 > 0) 蓝涨线[i] = 布外下轨[i];
               // 报警
               if(使用报警 && i == 0 && !已报涨)
               {
                  Alert("BBands going Up on ", _Symbol, "-", _Period);
                  已报涨 = true;
                  已报跌 = false;
               }
            }
            else
            {
               涨趋势箭[i] = 布外下轨[i];
               if(显示样线 > 0) 蓝涨线[i] = 布外下轨[i];
               涨信号箭[i] = -1;
            }
            
            if(显示信号样式 == 2) 涨趋势箭[i] = 0;
            
            跌信号箭[i] = -1;
            跌趋势箭[i] = -1.0;
            红跌线[i] = EMPTY_VALUE;
         }
         
         // 趋势向下时
         if(趋势 < 0)
         {
            if(显示信号样式 > 0 && 跌趋势箭[i+1] == -1.0)
            {
               跌信号箭[i] = 布外上轨[i];
               跌趋势箭[i] = 布外上轨[i];
               if(显示样线 > 0) 红跌线[i] = 布外上轨[i];
               if(使用报警 && i == 0 && !已报跌)
               {
                  Alert("BBands going Down on ", _Symbol, "-", _Period);
                  已报跌 = true;
                  已报涨 = false;
               }
            }
            else
            {
               跌趋势箭[i] = 布外上轨[i];
               if(显示样线 > 0) 红跌线[i] = 布外上轨[i];
               跌信号箭[i] = -1;
            }
            
            if(显示信号样式 == 2) 跌趋势箭[i] = 0;
            
            涨信号箭[i] = -1;
            涨趋势箭[i] = -1.0;
            蓝涨线[i] = EMPTY_VALUE;
         }
      }
   }

   return(rates_total);
}
//+------------------------------------------------------------------+
